require('http').createServer(function (req, res) {
    //BOOKS RESOURCE
    if ((req.url.match("^/books(.*)$"))) {
        processBook(req, res);
        return;
    }
    sendUnknownRequest(res);
}).listen(8888);

/**********************PROCESS ENTITIES*************************************/

//function findBooksWithPublisher(publisher) {
//
//}

function processBook(req, res) {
    var matchStrings = req.url.match("^/books/publisher/([a-z,0-9]+)$");

    if (matchStrings != null && req.method == "GET") {
        var publisherId = getIdPartOrSendUnknownRequest(res, matchStrings);
        var publisher = storage.getEntityWithType(publisherId, Publisher);
        checkEntityNotNull(publisher);

//        books = findBooksWithPublisher(publisher);
    }


    matchStrings = req.url.match("^/books/([a-z,0-9]+)$");
    if (matchStrings == null) {
        serveFunctions.serveGetAllEntities(req, res, Book);
        serveFunctions.serverNewEntity(req, res, function (parsedData) {
            var newBook = new Book(parsedData.name);
            copyDataToEntity(newBook, parsedData);
            storage.addEntity(newBook);
            return newBook.id;
        });
        return;
    }

    var bookId = getIdPartOrSendUnknownRequest(res, matchStrings);
    var book = storage.getEntityWithType(bookId, Book);
    checkEntityNotNull(res, book);
    serveFunctions.serveGetOne(req, res, book);
    serveFunctions.serveEditEntity(req, res, book);
}


/************************RESPONSE UTIL*********************/

getIdPartOrSendUnknownRequest = function (res, matchStrings) {
    var idPart = matchStrings[1];
    if (idPart == null) {
        res.writeHead(400);
        res.end();
    }
    else {
        return idPart;
    }
}

sendUnknownRequest = function (res) {
    res.writeHead(400);
    res.end();
}

checkEntityNotNull = function (res, entity) {
    if (entity == null) {
        res.writeHead(404);
        res.end();
    }
}

/**********************MODEL*************************************/

var globalIdGenerator = 0;

function Author(name) {
    this.id = globalIdGenerator++;
    this.name = name;
//    this.books = new Array();
}

function Book(name) {
    this.id = globalIdGenerator++;
    this.name = name;
    this.author = null;
    this.publishers = new Array();
}

function Publisher(name) {
    this.id = globalIdGenerator++;
    this.name = name;
//    this.books = new Array();
    this.shops = new Array();
    this.country = null;
}

function Country(name) {
    this.id = globalIdGenerator++;
    this.name = name;
//    this.publishers = new Array();
}

function Shop(name) {
    this.id = globalIdGenerator++;
    this.name = name;
//    this.publishers = new Array();
}

/**********************DEF TEST VALUES*************************************/

var authorKC = new Author("Capek");
var countryCZ = new Country("cz");
var shopEBooks = new Shop("EBooks");
var shopBorovsky = new Shop("Obchod Borovsky");
var publisherEBooks = new Publisher("EDigRead");
var publisherBorovsky = new Publisher("Borovsky");
var bookBN = new Book("bila nemoc");
var bookFoltyn = new Book("foltyn");

bookBN.author = authorKC;
bookBN.publishers.push(publisherEBooks)

bookFoltyn.author = authorKC;
bookFoltyn.publishers.push(publisherEBooks);
bookFoltyn.publishers.push(publisherBorovsky);

publisherEBooks.country = countryCZ;
publisherEBooks.shops = shopEBooks;

publisherBorovsky.country = countryCZ;
publisherBorovsky.shops = shopEBooks;


/**********************STORAGE*************************************/
var storage = {
    entities: [
        authorKC, countryCZ, shopEBooks, shopBorovsky, publisherEBooks, publisherBorovsky, bookBN, bookFoltyn
    ],

    getEntity: function (id) {
        for (var i = 0; i < this.entities.length; i++) {
            if (this.entities[i].id == id) {
                return this.entities[i];
            }
        }
        return null;
    },

    getEntityWithType: function (id, type) {
        var entity = this.getEntity(id);
        if (entity instanceof type) {
            return entity;
        }
        return null;
    },

    addEntity: function (entity) {
        var entity = this.entities.push(entity);
    },

    removeEntity: function (id) {
        for (var i = 0; i < this.entities.length; i++) {
            var entity = this.entities[i];
            if (entity.id == id) {
                this.entities.splice(i, 1);
                delete entity;
                return;
            }
        }
    },

    getEntitiesByType: function (type) {
        result = new Array();
        for (var i = 0; i < this.entities.length; i++) {
            if (this.entities[i] instanceof type) {
                result.push(this.entities[i]);
            }
        }
        return result;
    },

    updateEntity: function (entity, data) {
        copyDataToEntity(entity, data);
    }
}

copyDataToEntity = function (entity, data) {
    if (entity instanceof Book) {
        entity.name = data.name;
        var authorId = data.authorId;
        if (authorId != null) {
            entity.author = storage.getEntityWithType(authorId, Author);
        } else {
            entity.author = null;
        }

        var publishersId = data.publishersId;
        var publishers = new Array();
        if (publishersId != null) {
            for (var i = 0; i < publishersId.length; i++) {
                publishers.push(storage.getEntityWithType(publishersId[i], Publisher));
            }
        }
        entity.publishers = publishers;
    }
}


/*********************SERVE FUNCTIONS*****************/
var serveFunctions = {
    serveGetOne: function (req, res, object) {
        if (req.method == "GET") {
            res.writeHead(200, {'Content-Type': 'application/json'});
            res.write(JSON.stringify(object));
            res.end();
        }
    },

    serverNewEntity: function (req, res, funnction) {
        if (req.method == "POST") {
            req.setEncoding('utf8');
            req.on('data', function (data) {
                var parsedData = JSON.parse(data);
                var newId = funnction(parsedData);
                res.writeHead(201, {'Location': req.url + "/" + newId});
                res.end();
            });
        }
    },

    serveEditEntity: function (req, res, object) {
        if (req.method == "POST") {
            res.writeHead(200, {'Content-Type': 'application/json'});
            req.setEncoding('utf8');
            req.on('data', function (data) {
                var parsedData = JSON.parse(data);
                res.write(data);
                storage.updateEntity(object, parsedData);
                res.end();
            });
        }
    },

//    serveDelete: function (req, res, entityId) {
//        if (req.method == "DELETE") {
//            res.writeHead(200, {'Content-Type': 'application/json'});
//            storage.removeEntity(entityId);
//            res.end();
//        }
//    },

    serveGetAllEntities: function (req, res, type) {
        if (req.method == "GET") {
            res.writeHead(200, {'Content-Type': 'application/json'});
            res.write(JSON.stringify(storage.getEntitiesByType(type)));
            res.end();
            return;
        }
    }
}
